<!--
 * @Author: Lw
 * @Date: 2022-09-05 11:24:20
 * @LastEditors: LHL
 * @LastEditTime: 2022-10-19 10:51:43
-->
<template>
  <n-spin :show="loading">
    <n-form
      ref="formRef"
      style="margin-bottom: -24px"
      :model="form"
      :rules="rules"
      :inline="inline"
      label-placement="left"
      :label-width="labelWidth"
      :label-align="labelAlign"
      require-mark-placement="left"
      size="large"
    >
      <n-grid :cols="cols" :collapsed="collapsed" :collapsed-rows="1" :x-gap="40" :y-gap="0">
        <n-form-item-gi
          v-for="(item, index) in options"
          :key="index"
          :label="item.label?.length > 0 ? `${item.label} :` : ''"
          :path="item.key"
          :span="item.span || 1"
          style="width: 100%"
        >
          <!-- 自定义编辑 -->
          <slot v-if="item.type == 'slot'" :key="item.key" :value="form[item.key]" name="formItem"></slot>
          <!-- 只读 -->
          <span v-else-if="onlyRead">{{ onlyReadData(item) }}</span>
          <!-- 文本 -->
          <n-input
            v-else-if="['text', 'textarea', 'password'].includes(item.type)"
            v-model:value="form[item.key]"
            :type="item.type"
            :maxlength="item.maxlength"
            :minlength="item.minlength"
            :show-password-on="item.type === 'password' ? 'click' : undefined"
            :placeholder="item.placeholder || `请输入${item.label}`"
            :disabled="item.disabled"
            :clearable="item.clearable || true"
            style="width: 100%"
          />

          <!-- 计数器 -->
          <n-input-number
            v-else-if="item.type == 'number'"
            v-model:value="form[item.key]"
            :max="item.max"
            :min="item.min"
            :show-button="item.showButton || false"
            :placeholder="item.placeholder || `请输入${item.label}`"
            :disabled="item.disabled"
            :clearable="item.clearable || true"
            style="width: 100%"
          >
            <!-- 单位 -->
            <template #suffix> {{ item.unit }} </template>
          </n-input-number>

          <!-- 选择器 -->
          <n-select
            v-else-if="item.type == 'select'"
            v-model:value="form[item.key]"
            :options="item.options"
            :multiple="item.multiple"
            :filterable="item.filterable || true"
            :remote="item.remote || false"
            :placeholder="item.placeholder || `请选择${item.label}`"
            :disabled="item.disabled"
            :clearable="item.clearable || true"
            :clear-filter-after-select="item.clearFilterAfterSelect || false"
            :tag="item.tag === undefined ? false : item.tag"
            :show="item.show"
            :show-arrow="item.showArrow === undefined ? true : item.showArrow"
            style="width: 100%"
            @update-value="
              (value) => {
                change({
                  key: item.key,
                  value: value,
                  oldValue: form[item.key],
                })
              }
            "
          >
          </n-select>
          <!-- 树型选择 -->
          <n-tree-select
            v-else-if="item.type == 'treeselect'"
            v-model:value="form[item.key]"
            :options="item.options"
            :placeholder="item.placeholder || '请选择'"
            :disabled="item.disabled"
            :clearable="item.clearable || true"
            style="width: 100%"
          />
          <!-- 级联选择器 -->
          <n-cascader
            v-else-if="item.type == 'cascader'"
            v-model:value="form[item.key]"
            :options="item.options"
            :placeholder="item.placeholder || `请选择${item.label}`"
            :disabled="item.disabled"
            :clearable="item.clearable || true"
            :multiple="item.multiple || false"
            :filterable="item.filterable || false"
            :remote="item.remote || true"
            :cascade="item.cascade == undefined ? true : item.cascade"
            :check-strategy="item.checkStrategy || 'all'"
            :show-path="item.showPath"
            :label-field="item.labelField || 'label'"
            :value-field="item.valueField || 'value'"
            :children-field="item.childrenField || 'children'"
            :allow-checking-not-loaded="item.allowCheckingNotLoaded || false"
            style="width: 100%"
          />
          <!-- 开关 -->
          <n-switch
            v-else-if="item.type == 'switch'"
            v-model:value="form[item.key]"
            :disabled="item.disabled"
            :rail-style="item.railStyle"
          >
            <template #checked>
              {{ item.openText || '是' }}
            </template>
            <template #unchecked>
              {{ item.closeText || '否' }}
            </template>
          </n-switch>
          <!-- 单选 -->
          <n-radio-group
            v-else-if="item.type == 'radio'"
            v-model:value="form[item.key]"
            :name="`${item.key}-group`"
            :disabled="item.disabled"
          >
            <n-space>
              <n-radio v-for="(i, index) in item.options" :key="index" :value="i.value" :disabled="i.disabled">
                {{ i.label }}
              </n-radio>
            </n-space>
          </n-radio-group>
          <!-- 复选框 -->
          <n-checkbox-group
            v-else-if="item.type == 'checkbox'"
            v-model:value="form[item.key]"
            :disabled="item.disabled"
          >
            <n-space>
              <n-checkbox v-for="(i, index) in item.options" :key="index" :value="i.value" :disabled="i.disabled">
                {{ i.label }}
              </n-checkbox>
            </n-space>
          </n-checkbox-group>
          <!-- 提及 -->
          <n-mention
            v-else-if="item.type == 'mention'"
            v-model:value="form[item.key]"
            v-bind="item"
            type="text"
            :disabled="item.disabled"
            :clearable="item.clearable || true"
          />
          <!-- 时间选择器  data: item.options.find((x) => x.value === form[item.key]), -->
          <n-time-picker
            v-else-if="item.type == 'timePicker'"
            v-model:formatted-value="form[item.key]"
            :format="item.format || 'HH:mm:ss'"
            :value-format="item.valueFormat || 'HH:mm:ss'"
            :placeholder="item.placeholder || '请选择时间'"
            :disabled="item.disabled || false"
            :clearable="item.clearable || true"
            :actions="item.actions || null"
            :update-value-on-close="true"
            style="width: 100%"
          />

          <!-- 日期选择器 -->
          <n-date-picker
            v-else-if="
              ['date', 'datetime', 'daterange', 'datetimerange', 'month', 'year', 'quarter'].includes(item.type)
            "
            v-model:formatted-value="form[item.key]"
            :type="item.type"
            :value-format="item.valueFormat || 'yyyy-MM-dd'"
            :format="item.format || 'yyyy-MM-dd'"
            :placeholder="item.placeholder || '请选择日期'"
            :disabled="item.disabled || false"
            :clearable="item.clearable || true"
            :actions="item.actions || null"
            :close-on-select="true"
            :shortcuts="item.shortcuts || undefined"
            :update-value-on-close="true"
            style="width: 100%"
            :default-time="['00:00:00', '23:59:59']"
            :is-date-disabled="item.dateDisabled || null"
            :is-time-disabled="item.timeDisabled || null"
          />

          <!-- 上传 -->
          <!-- <UploadImg
            v-else-if="item.type == 'image'"
            v-model:file-list="form[item.key]"
            :max="item.max || 1"
            :data="item.data"
            :disabled="item.disabled"
          />

          <UploadFile
            v-else-if="item.type === 'file'"
            v-model:file-list="form[item.key]"
            :max="item.max || 1"
            :data="item.data"
            :disabled="item.disabled"
          />

          <DraggerUpload
            v-else-if="item.type === 'dragger'"
            v-model:file-list="form[item.key]"
            :max="item.max || 1"
            :data="item.data"
            :disabled="item.disabled"
          /> -->
        </n-form-item-gi>
        <n-form-item-gi :span="cols > 5 ? Math.floor(cols / 5) : 1" size="large" v-if="isBtnItem">
          <slot name="btnItem"></slot>
        </n-form-item-gi>
      </n-grid>
    </n-form>
  </n-spin>
</template>

<script setup name="CustomForm">
  // import { UploadFile, UploadImg, DraggerUpload } from '@/components/Upload'

  const emits = defineEmits(['change'])
  const props = defineProps({
    loading: {
      type: Boolean,
    },
    onlyRead: {
      type: Boolean,
      default: false,
    },
    isBtnItem: {
      type: Boolean,
      default: false,
    },
    inline: {
      type: Boolean,
    },
    labelAlign: {
      type: String,
      default: 'left',
    },
    labelWidth: {
      type: String,
      default: 'auto',
    },
    collapsed: {
      type: Boolean,
      default: false,
    },
    cols: {
      type: Number,
      default: 2,
    },
    options: {
      type: Array,
      required: true,
    },
    form: {
      type: Object,
      required: true,
      default: () => {},
    },
    rules: {
      type: Object,
      default: () => {},
    },
  })

  const formRef = ref()
  // 验证
  const validate = () => {
    let res = null
    return formRef.value
      ?.validate((errors) => {
        if (!errors) {
          // $message.success("Valid");
          res = true
        } else {
          // console.log('errors>>>', errors)
          // $message.error('请输入必填项')
          res = false
        }
      })
      .then(() => {
        return Promise.resolve(res)
      })
      .catch((error) => {
        return Promise.resolve(res)
      })
  }
  // 清除验证结果
  const clearValidate = () => {
    formRef.value?.restoreValidation()
  }

  // 表单变化事件
  function change(parameters) {
    const { value, oldValue, key } = parameters
    if (oldValue !== value) {
      emits('change', {
        key,
        value,
      })
    }
  }

  /**
   * 平铺树形结构
   */
  function TreeDataFlat(data, childrenKey = 'children') {
    let arr = []
    const flat = (fData) => {
      if (fData && fData.length > 0) {
        fData.map((item) => {
          arr.push(item)
          flat(item[childrenKey])
        })
      }
    }
    flat(data)
    return arr
  }

  // 查看模式数据回显
  function onlyReadData(item) {
    const { type, key, options } = item
    const val = props.form[key]
    if (type === 'select') {
      // 选择
      let nameList = []
      if (item.tag) {
        // 单选
        nameList = val
      } else {
        // 兼容多选
        const valList = val || val === 0 || val === '0' ? (val + '').split(',') : []
        nameList = (options || [])
          .filter((item) => valList.indexOf(item[[item.valueField || 'value']] + '') != -1)
          .map((item) => item[item.labelField || 'label'])
      }

      return nameList.length > 0 ? nameList.join(', ') : val || val === +val ? val : '-'
    } else if (type === 'cascader') {
      // 级联
      const childrenField = item.childrenField === undefined ? 'children' : item.childrenField
      const valueField = item.valueField === undefined ? 'value' : item.valueField
      const labelField = item.labelField === undefined ? 'label' : item.labelField
      const flatArr = TreeDataFlat(options || [], childrenField)
      const labelList = flatArr?.filter((item) => val?.indexOf(item[valueField]) != -1).map((item) => item[labelField])

      return labelList.length > 0 ? labelList.join(', ') : val || val === +val ? val : '-'
    } else if (type === 'switch') {
      // 开关
      const checkedVal = item.checkedValue === undefined ? true : item.checkedValue
      const unCheckedVal = item.checkedValue === undefined ? false : item.checkedValue

      return val == checkedVal ? item.openText || '是' : val == unCheckedVal ? item.closeText || '否' : val
    } else if (val === +val) {
      // 判断为数字
      return val
    } else {
      return val?.length > 0 ? val : '-'
    }
  }

  defineExpose({
    validate,
    clearValidate,
  })
</script>

<style lang="scss" scoped></style>
